import { ISOFile } from 'mp4box'
class WsPlayer {
  private videoId: string;
  private wsUrl: string;
  private ws: WebSocket | null;
  private frameQueue: ArrayBuffer[];

  constructor(videoId: string, wsUrl: string) {
    this.videoId = videoId;
    this.wsUrl = wsUrl;
    this.ws = null;
    this.frameQueue = [];
  }

  open(): void {
    let sourcebuffer: SourceBuffer | null = null;
    this.ws = new WebSocket(this.wsUrl);
    this.ws.binaryType = 'arraybuffer';
    let firstMessage = true;

    const demuxMoov = (info: any) => {
      let codecs: string[] = [];
      for (let i = 0; i < info.tracks.length; i++) {
        codecs.push(info.tracks[i].codec);
      }
      console.log(codecs);
      let video = document.getElementById(this.videoId) as HTMLVideoElement;
      let mediasource = new MediaSource();
      video.src = URL.createObjectURL(mediasource);
      let prePos = 0;
      mediasource.onsourceopen = () => {
        sourcebuffer = mediasource.addSourceBuffer('video/mp4; codecs="' + codecs.join(', ') + '"');
        sourcebuffer.onupdateend = () => {
          let pos = video.currentTime;
          if (video.buffered.length > 0) {
            let start = video.buffered.start(video.buffered.length - 1);
            let end = video.buffered.end(video.buffered.length - 1);

            if (pos < start) {
              video.currentTime = start;
            }

            if (pos > end) {
              video.currentTime = start;
            }

            if (pos - prePos !== 0 && end - pos > 3) {
              video.currentTime = end;
            }

            for (let i = 0; i < video.buffered.length - 1; i++) {
              let prestart = video.buffered.start(i);
              let preend = video.buffered.end(i);
              if (!sourcebuffer!.updating) {
                sourcebuffer!.remove(prestart, preend);
              }
            }

            if (pos - start > 10 && !sourcebuffer!.updating) {
              sourcebuffer!.remove(0, pos - 3);
            }

            if (end - pos > 10 && !sourcebuffer!.updating) {
              sourcebuffer!.remove(0, end - 3);
            }
          }
          prePos = pos;
        };
      };
    };

    this.ws.onmessage = function (e) {
      if (firstMessage) {
        firstMessage = false;
        let moov = e.data;
        let mp4Box = new ISOFile(null);
        mp4Box.onReady = demuxMoov;
        moov.fileStart = 0;
        mp4Box.appendBuffer(moov);
      }
      this.frameQueue.push(e.data);
      if (!sourcebuffer || sourcebuffer.updating) {
        return;
      }
      if (this.frameQueue.length === 1) {
        sourcebuffer.appendBuffer(this.frameQueue.shift()!);
      } else {
        let byteLength = 0;
        for (const qnode of this.frameQueue) {
          byteLength += qnode.byteLength;
        }
        let mp4buf = new Uint8Array(byteLength);
        let offset = 0;
        for (const qnode of this.frameQueue) {
          let frame = new Uint8Array(qnode);
          mp4buf.set(frame, offset);
          offset += qnode.byteLength;
        }
        sourcebuffer.appendBuffer(mp4buf);
        this.frameQueue.splice(0, this.frameQueue.length);
      }
    }.bind(this);
  }

  close(): void {
    this.ws?.close();
  }
}

export default WsPlayer
